#include "Common.h"
#include "App_Files.h"

#include "Uart/AppLibUart_Base.hpp"
#include "SystemV/AppLibSystemV_Msg.hpp"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

typedef struct __APP_LIB_UART_CTRL_s__
{
    SINT32              iMsgFd;
    BOOL                bIsStop;
    pthread_t           stRecMsg;
    pthread_t           stSplitMsg;
    pthread_t           stProcMsg;
    pthread_mutex_t     stLock;
    APP_LIB_UART_CFG_s  astUart[BSP_UART_CHANNEL_MAX];
} APP_LIB_UART_CTRL_s;

static APP_LIB_UART_CTRL_s gstUart = {.iMsgFd = -1};

/**********************************************************
 * Function Name:       AppLibUart_SendMsg
 * Description:         串口发送
 * Parameters[in]:      IN BSP_UART_CHANNEL_e enChan
                        IN UINT8 *send_buf
                        IN INT32 data_len
 * Parameters[out]:     void
 * ReturnValue:         ULONG
 * Author:              liuke
 * Date:                2025.11.06
***********************************************************/
ULONG AppLibUart_SendMsg(IN BSP_UART_CHANNEL_e enChan, IN UINT8 *send_buf, IN SINT32 data_len)  
{  
    return BspUart_Write(enChan, send_buf, data_len);
}

/**********************************************************
 * Function Name:       AppLibUart_PushPacket
 * Description:         数据包入队列
 * Parameters[in]:      IN SLONG s64Type
                        IN UINT8 *pucPacket
                        IN UINT16 usLen
 * Parameters[out]:     void
 * ReturnValue:         ULONG
 * Author:              liuke
 * Date:                2025.11.06
***********************************************************/
ULONG AppLibUart_PushPacket(IN SLONG s64Type, IN UINT8 *pucPacket, IN UINT16 usLen)
{
    UINT8 szBuf[1024] = {0};
    APP_LIB_SYSTEM_V_MSG_s *pstMsg = (APP_LIB_SYSTEM_V_MSG_s *)szBuf;

    pstMsg->lType = s64Type;
    pstMsg->usLen = usLen;
    return AppLibSystemV_MsgSendWait(gstUart.iMsgFd, pstMsg);
}

/**********************************************************
 * Function Name:       AppLibUart_PushPacket
 * Description:         数据包出队列
 * Parameters[in]:      IN SLONG s64Type
                        INOUT UINT8 *pucPacket
                        IN UINT16 usLen
 * Parameters[out]:     INOUT UINT8 *pucPacket
 * ReturnValue:         ULONG
 * Author:              liuke
 * Date:                2025.11.06
***********************************************************/
ULONG AppLibUart_PopPacket(IN SLONG s64Type, INOUT UINT8 *pucPacket, IN UINT16 usLen)
{
    UINT8 szBuf[1024] = {0};
    APP_LIB_SYSTEM_V_MSG_s *pstMsg = (APP_LIB_SYSTEM_V_MSG_s *)szBuf;

    pstMsg->lType = s64Type;
    pstMsg->usLen = usLen;
    return AppLibSystemV_MsgRecvWait(gstUart.iMsgFd, pstMsg);
}

void *AppLibUart_RecvMsg(void * pParam)
{
    UINT8 szBuf[UART_RX_BUFF_SIZE] = {0};
    SINT32 i = 0;
    SINT32 len = 0;
    SINT32 fs_sel = 0;
    SINT32 iFdMax = 0;
    fd_set fs_read;  
    struct timeval time;
    APP_LIB_UART_CFG_s *pstCfg = NULL;

    while (1)
    {
        FD_ZERO(&fs_read);
        pthread_mutex_lock(&gstUart.stLock);
        for (i = 0; i < BSP_UART_CHANNEL_MAX; i++)
        {
            pstCfg = &gstUart.astUart[i];
            if (pstCfg->iFd >= 0)
            {
                FD_SET(pstCfg->iFd, &fs_read);
                if (iFdMax < (pstCfg->iFd))
                {
                    iFdMax = pstCfg->iFd;
                }
            }
        }
        
        pthread_mutex_unlock(&gstUart.stLock);

        time.tv_sec = 1;  
        time.tv_usec = 0;  
       
        fs_sel = select(iFdMax + 1, &fs_read, NULL, NULL, &time);  
        if(fs_sel <= 0)
        {
            continue; 
        }  

        pthread_mutex_lock(&gstUart.stLock);
        for (i = 0; i < BSP_UART_CHANNEL_MAX; i++)
        {
            pstCfg = &gstUart.astUart[i];
            if ((pstCfg->iFd >= 0) &&
                (FD_ISSET(pstCfg->iFd,&fs_read)))
            {
                len = AppFile_Read(BSP_UART_CHANNEL_0, szBuf, sizeof(szBuf)); 
                AppLibUart_PushPacket(BSP_UART_CHANNEL_0 + APP_LIB_MSG_TYPE_RECV, szBuf, len);
                
                memset(szBuf, 0, sizeof(szBuf));
            }
        }
        pthread_mutex_unlock(&gstUart.stLock);
    }
}

void *AppLibUart_SplitRecvPacket(void *pParam)
{
	int rx_size = 0;
    BSP_UART_CHANNEL_e enChan = *((BSP_UART_CHANNEL_e *)pParam);
	UINT8 tmp_buffer[UART_RX_BUFF_SIZE] = {0};
    APP_LIB_UART_CFG_s *pstUartCfg = &gstUart.astUart[enChan];

    while (1)
    {
        rx_size = AppLibUart_PopPacket(enChan + APP_LIB_MSG_TYPE_RECV, tmp_buffer, sizeof(tmp_buffer));
        if (rx_size)
        {
            pthread_mutex_lock(&gstUart.stLock);
            if ((pstUartCfg->pfSplitPkgCB != NULL))
            {
                pstUartCfg->pfSplitPkgCB(tmp_buffer, rx_size);
            }
            pthread_mutex_unlock(&gstUart.stLock);
        } 
    }

    return NULL;
}

void *AppLibUart_HandlePacket(void * pParam)
{
	int rx_size = 0;
	UINT8 tmp_buffer[UART_RX_BUFF_SIZE] = {0};
    BSP_UART_CHANNEL_e enChan = *((BSP_UART_CHANNEL_e *)pParam);
    APP_LIB_UART_CFG_s *mpkg = &gstUart.astUart[enChan];

    while (1)
    {
        rx_size = AppLibUart_PopPacket(enChan + APP_LIB_MSG_TYPE_SPLITE, tmp_buffer, sizeof(tmp_buffer));
        if (rx_size != 0)
        {
            continue;
        }

        pthread_mutex_lock(&gstUart.stLock);
        if ((mpkg->pfHandlePkgCB != NULL))
        {
            mpkg->pfHandlePkgCB(tmp_buffer, rx_size);
        }
        pthread_mutex_unlock(&gstUart.stLock);
    }

    return NULL;
}

ULONG AppLibUart_Register(INOUT APP_LIB_UART_CFG_s *pstUartCfg)
{
    SINT32 iRet = 0;
    ULONG ulRet = STAT_SUCCESS;
    APP_LIB_UART_CFG_s *pstUart = NULL;
    
    if (pstUart == NULL || pstUart->eChannel >= BSP_UART_CHANNEL_MAX)
    {
        return STAT_ERR_INVAILD_PARAM;
    }

    pstUart = &gstUart.astUart[pstUart->eChannel];

    pthread_mutex_lock(&gstUart.stLock);
    
    memset(pstUart, 0, sizeof(*pstUart));

    pstUart->iFd = -1;
    pstUart->eChannel = pstUartCfg->eChannel;
    pstUart->pfHandlePkgCB = pstUartCfg->pfHandlePkgCB;
    pstUart->pfSplitPkgCB = pstUartCfg->pfSplitPkgCB;

    ulRet = BspUart_Open(pstUart->eChannel, &pstUart->iFd);
    if (ulRet != STAT_SUCCESS)
    {
        memset(pstUart, 0, sizeof(*pstUart));
        pstUart->iFd = -1;
    }

    /* create pthread */
    iRet = pthread_create(&gstUart.stProcMsg, NULL, AppLibUart_SplitRecvPacket, (void *)&pstUartCfg->eChannel);
    if (iRet != 0)
    {
        return STAT_ERR_THREAD_CREATE;
    }

    iRet = pthread_detach(gstUart.stProcMsg);
    if (iRet != 0)
    {
        return STAT_ERR_THREAD_DETACH;
    }

    /* create pthread */
    iRet = pthread_create(&gstUart.stSplitMsg, NULL, AppLibUart_HandlePacket, (void *)&pstUartCfg->eChannel);
    if (iRet != 0)
    {
        return STAT_ERR_THREAD_CREATE;
    }

    iRet = pthread_detach(gstUart.stSplitMsg);
    if (iRet != 0)
    {
        return STAT_ERR_THREAD_DETACH;
    }


    pthread_mutex_unlock(&gstUart.stLock);

    return ulRet;
}

ULONG AppLibUart_init(void)
{
    SINT32 iRet = 0;
    ULONG ulRet = STAT_SUCCESS;

    memset(gstUart.astUart, 0, sizeof(gstUart.astUart));

    pthread_mutex_init(&gstUart.stLock, NULL);

    /* 创建消息队列 */
    ulRet = AppLibSystemV_MsgCreate((CHAR *)APP_LIB_UART_MSG_PATH, &gstUart.iMsgFd);
    if (ulRet != STAT_SUCCESS)
    {
        return ulRet;
    }

    /* create recv for all channel */
    iRet = pthread_create(&gstUart.stRecMsg, NULL, AppLibUart_RecvMsg, NULL);
    if (iRet != 0)
    {
        return STAT_ERR_THREAD_CREATE;
    }

    iRet = pthread_detach(gstUart.stRecMsg);
    if (iRet != 0)
    {
        return STAT_ERR_THREAD_DETACH;
    }

    return ulRet;
}

void CommUart_destory(void)
{
    SINT32 iRet = 0;
    UINT32 uRet = STAT_SUCCESS;

    iRet = pthread_cancel(gstUart.stRecMsg);
    if (iRet != 0)
    {
        printf("[%s %d] err %d [%s]\n", __FUNCTION__, __LINE__, errno, strerror(errno));
    }

    iRet = pthread_cancel(gstUart.stProcMsg);
    if (iRet != 0)
    {
        printf("[%s %d] err %d [%s]\n", __FUNCTION__, __LINE__, errno, strerror(errno));
    }

    uRet = AppLibSystemV_MsgDestory(&gstUart.iMsgFd);
    if (uRet != STAT_SUCCESS)
    {
        printf("[%s %d] MsgQueue_destory fail %u\n", __FUNCTION__, __LINE__, uRet);
    }

    pthread_mutex_destroy(&gstUart.stLock);
}
